﻿
using Test30.Core;

namespace Test30.Engine
{
    public class FeatureCreepGenerator : IDungeonGenerator, IFeatureWriter
    {

        #region IDungeonGenerator Members
        public void Create(Dungeon dungeon, bool isDescending, int depth, object optionsObj)
        {
            _options = (FeatureCreepGeneratorOptions)optionsObj;

            _dungeon = dungeon;


            _dungeon.Entities.Clear();
            _dungeon.Items.Clear();

            MakeDungeon(depth);
        }
        #endregion

        private void MakeDungeon(int depth)
        {
            _dungeon.Tiles.Fill(pos => new Tile(TileType.Wall));

            _factory = new FeatureFactory(this, depth);

            _factory.CreateFeature();
        }

        #region IFeatureWriter Members
        public Rect Bounds => _dungeon.Bounds;
        public Content Content => _dungeon.Game.Content;
        public FeatureCreepGeneratorOptions Options => _options;

        public bool IsOpen(Rect rect, Vec? exception)
        {
            // must be totally in bounds
            if (!_dungeon.Bounds.Contains(rect)) return false;

            // and not cover the starting grid
            if (rect.Contains(_startPos)) return false;

            // or something connected to it
            foreach (Vec edge in rect.Trace())
            {
                // allow the exception
                if (exception.HasValue && (exception.Value == edge)) continue;

                if (_dungeon.Tiles[edge].Type != TileType.Wall) return false;
            }

            return true;
        }

        public void SetTile(Vec pos, TileType type)
        {
            _dungeon.Tiles[pos].Type = type;
        }

        public void SetDirty(Vec pos, bool dirty)
        {
            _dungeon.Tiles[pos].Dirty = dirty;
        }

        public void SetStartPos(Vec pos)
        {
            _startPos = pos;
        }

        public void LightRect(Rect bounds, int depth)
        {
            if ((depth <= Rng.Int(1, 80)))
            {
                foreach (Vec pos in bounds.Inflate(1))
                {
                    _dungeon.SetTilePermanentLit(pos, true);
                }
            }
        }

        public void AddEntity(Entity entity,int depth)
        {
            _dungeon.Entities.Add(entity,depth);
        }

        public TileType GetTile(Vec pos)
        {
            return _dungeon.Tiles[pos].Type;
        }

        public TileType GetTile(int x, int y)
        {
            return GetTile(new Vec(x, y));
        }

        public bool GetDirty(Vec pos)
        {
            return _dungeon.Tiles[pos].Dirty;
        }

        public void Populate(Vec pos, int monsterDensity, int itemDensity, int depth)
        {
            if (_dungeon.Tiles[pos].IsPassable)
            {
                // place a monster
                if ((_dungeon.Entities.GetAt(pos) == null) && (Rng.Int(1000) < monsterDensity + (depth / 4)))
                {
                    Monster.AddRandom(_dungeon, depth, pos, depth);
                }

                // place an item
                if (Rng.Int(1000) < itemDensity + (depth / 4))
                {
                    Race race = Race.Random(_dungeon, depth, false);
                    race.PlaceDrop(_dungeon, pos);
                }
            }
        }
        #endregion

        private FeatureCreepGeneratorOptions _options;
        private Dungeon _dungeon;
        private FeatureFactory _factory;
        private Vec _startPos;

    }

}
